package top.yaofengqiao.springcloudsimple.demo.biz.domain.order.service.impl;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import top.yaofengqiao.springcloudsimple.common.constant.CommonConstant;
import top.yaofengqiao.springcloudsimple.common.constant.OrderConstant;
import top.yaofengqiao.springcloudsimple.common.constant.RechargeOrderStatus;
import top.yaofengqiao.springcloudsimple.common.constant.ResponseCode;
import top.yaofengqiao.springcloudsimple.common.util.AppException;
import top.yaofengqiao.springcloudsimple.demo.biz.domain.order.model.entity.OrderEntity;
import top.yaofengqiao.springcloudsimple.demo.biz.domain.order.repository.IRechargeOrderRepository;
import top.yaofengqiao.springcloudsimple.demo.biz.domain.order.service.IOrderService;
import top.yaofengqiao.springcloudsimple.demo.biz.domain.product.model.entity.ProductEntity;
import top.yaofengqiao.springcloudsimple.demo.biz.domain.product.service.IProductService;
import top.yaofengqiao.springcloudsimple.demo.biz.trigger.http.app.dto.CreateOrderDTO;
import top.yaofengqiao.springcloudsimple.demo.biz.trigger.listener.dto.OrderDeliverDTO;
import top.yaofengqiao.springcloudsimple.payment.api.IPaymentOrderDubboService;
import top.yaofengqiao.springcloudsimple.redis.starter.service.IRedisService;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Objects;

/**
 * @author yfq
 * @date 2024/6/14 11:34
 * @description
 */
@Slf4j
@Service
public class OrderService implements IOrderService {
    @Resource
    private IRechargeOrderRepository rechargeOrderRepository;
    @Resource
    private IProductService productService;
    @Resource
    private IRedisService redisService;
    @DubboReference
    private IPaymentOrderDubboService paymentOrderDubboService;

    @Override
    public Long createOrder(CreateOrderDTO createOrderDTO, long userId) {
        String productId = createOrderDTO.getProductId();

        // 1. 查询是否有相同的未支付的订单
        OrderEntity orderEntity = rechargeOrderRepository.queryUnpaidOrder(productId, userId);
        if (orderEntity != null && Objects.equals(RechargeOrderStatus.CREATE.getStatus(), orderEntity.getOrderStatus())) {
            return orderEntity.getId();
        }

        // 2. 查询商品信息
        ProductEntity product = productService.queryProductById(productId);

        // 3. 构建订单
        OrderEntity order = OrderEntity.builder()
                .rechargeOrderNo(generateOrderNo())
                .userId(userId)
                .title(product.getTitle())
                .productType(product.getProductType())
                .productCode(productId)
                .originPrice(product.getPrice())
                .orderAmount(product.getPrice())
                .orderStatus(RechargeOrderStatus.CREATE.getStatus())
                .createTime(LocalDateTime.now())
                .build();

        // 4. 插入订单时加分布式锁，防止重复创建
        String key = OrderConstant.RedisConstant.ORDER_CREATE_LOCK + userId + productId;
        boolean tryLock = redisService.tryLock(key);
        if (!tryLock) throw new AppException(ResponseCode.ORDER_REPEAT_FAIL);

        try {
            long id = rechargeOrderRepository.save(order);

            if (id == -1) {
                log.error("订单创建异常：order：{}", JSON.toJSONString(order));
                throw new AppException(ResponseCode.ORDER_CREATE_FAIL);
            }

            return id;
        } finally {
            redisService.unLock(key);
        }
    }

    @Override
    public OrderEntity queryByOrderNo(String orderNo) {
        return rechargeOrderRepository.queryByOrderNo(orderNo);
    }

    @Override
    public OrderEntity queryByOrderId(long orderId) {
        return rechargeOrderRepository.queryByOrderId(orderId);
    }

    @Override
    public void orderDeliver(OrderDeliverDTO orderDeliverDTO) {
        // 1. 更新订单状态
        String orderNo = orderDeliverDTO.getOrderNo();
        OrderEntity orderEntity = OrderEntity.builder()
                .rechargeOrderNo(orderNo)
                .payAmount(orderDeliverDTO.getPayAmount())
                .payTime(orderDeliverDTO.getPayTime())
                .build();
        // 状态改变使用了乐观锁来保证消费消息的幂等性
        boolean updated = rechargeOrderRepository.changeToPayment(orderEntity);

        if (!updated) {
            log.error("订单发货状态更新失败：{}", JSON.toJSONString(orderDeliverDTO));
            return;
        }

        // 2. 商品发货
        log.info("订单开始发货【{}】", orderNo);
    }

    @Override
    public void orderClose(String rechargeOrderNo) {
        // 1. 取消充值订单
        rechargeOrderRepository.changeStatus(rechargeOrderNo, RechargeOrderStatus.CREATE, RechargeOrderStatus.CANCEL);

        // 2. 取消支付订单
        paymentOrderDubboService.paymentOrderClose(rechargeOrderNo);
    }

    /**
     * 生成订单号
     */
    private String generateOrderNo() {
        String key = OrderConstant.RedisConstant.ORDER_NO_SERIAL;
        long increment = redisService.getIncrement(key);

        if (increment == 1) redisService.expires(key, Duration.ofHours(1));

        String timeSerial = new SimpleDateFormat(CommonConstant.TIME_SERIAL).format(new Date());

        return OrderConstant.ORDER_NO_PREFIX + timeSerial + String.format("%04d", increment);
    }

}
